import akshare as ak
import pandas as pd
import numpy as np
import time
from datetime import datetime
import os
from send_mail import send_email

# 禁用代理
os.environ["http_proxy"] = ""
os.environ["https_proxy"] = ""

# ================== 股票外部筛选参数 ==================
TURNOVER_MIN = 5
TURNOVER_MAX = 10
MCAP_MAX = 200e8
PRICE_MIN = 3
PRICE_MAX = 30

# ================== 策略列表 ==================
strategies = [
    {
        "name": "策略A_阴线回调",
        "DEVIATION_RATIO10": 0.05,
        "DEVIATION_MUL30": 0.75,
        "RSI_MAX": 40,
        "VOL_RATIO_MIN": 1,
        "MA_SLOPE_MIN": 0
    },
    {
        "name": "策略B_低价反弹",
        "DEVIATION_RATIO10": 0.08,
        "DEVIATION_MUL30": 0.7,
        "RSI_MAX": 50,
        "VOL_RATIO_MIN": 0.8,
        "MA_SLOPE_MIN": -0.5
    }
]

# ================== 获取股票列表 ==================
print("获取全市场快照数据...")
spot_all = ak.stock_zh_a_spot_em()
spot_filtered = spot_all[
    (spot_all["换手率"].astype(float).between(TURNOVER_MIN, TURNOVER_MAX)) &
    (spot_all["流通市值"].astype(float) * 1e8 <= MCAP_MAX) &
    (spot_all["最新价"].astype(float).between(PRICE_MIN, PRICE_MAX)) &
    (~spot_all["名称"].str.startswith("ST")) &
    (~spot_all["代码"].str.startswith(("300", "301")))
]
codes = spot_filtered["代码"].tolist()
spot_map = spot_filtered.set_index("代码").to_dict(orient="index")
print(f"初筛剩余 {len(codes)} 只股票...")

# ================== 循环策略 ==================
today_str = datetime.today().strftime("%Y_%m_%d")
output_files = []

for strategy in strategies:
    results = []
    name = strategy["name"]
    DEVIATION_RATIO10 = strategy["DEVIATION_RATIO10"]
    DEVIATION_MUL30 = strategy["DEVIATION_MUL30"]
    RSI_MAX = strategy["RSI_MAX"]
    VOL_RATIO_MIN = strategy["VOL_RATIO_MIN"]
    MA_SLOPE_MIN = strategy["MA_SLOPE_MIN"]

    print(f"\n开始执行策略: {name}")

    for code in codes:
        try:
            daily = ak.stock_zh_a_daily(symbol=code, adjust="qfq")
            if len(daily) < 35:
                continue

            # 均线
            for w in [5,10,20,30]:
                daily[f"ma{w}"] = daily["close"].rolling(w).mean()
            daily["vol_ma5"] = daily["volume"].rolling(5).mean()

            latest = daily.iloc[-1]
            spot = spot_map.get(code)
            if not spot:
                continue

            turnover = float(spot["换手率"])
            mcap = float(spot["流通市值"]) * 1e8
            stock_name = spot["名称"]

            # RSI
            delta = daily["close"].diff()
            up = delta.clip(lower=0)
            down = -1*delta.clip(upper=0)
            roll_up = up.rolling(14).mean()
            roll_down = down.rolling(14).mean()
            rsi = 100 - 100 / (1 + roll_up/roll_down)
            latest_rsi = rsi.iloc[-1]

            # 均线斜率
            ma5_slope = daily["ma5"].iloc[-1] - daily["ma5"].iloc[-2]
            ma10_slope = daily["ma10"].iloc[-1] - daily["ma10"].iloc[-2]

            # 量能
            vol_ratio = daily["volume"].iloc[-1] / daily["vol_ma5"].iloc[-1]

            # 条件筛选
            cond1 = latest["close"] < latest["open"]
            cond2 = (latest["ma20"] < latest["ma5"]) and (latest["ma20"] < latest["ma10"])
            cond3 = (latest["ma30"] < latest["ma5"]) and (latest["ma30"] < latest["ma10"])
            cond4 = latest["ma10"]*(1-DEVIATION_RATIO10) <= latest["close"] <= latest["ma10"]*(1+DEVIATION_RATIO10)
            cond5 = latest["close"] > latest["ma20"]*DEVIATION_MUL30 and latest["close"] > latest["ma30"]*DEVIATION_MUL30
            cond6 = turnover >= TURNOVER_MIN and turnover <= TURNOVER_MAX
            cond7 = mcap <= MCAP_MAX
            cond8 = PRICE_MIN <= latest["close"] <= PRICE_MAX
            cond9 = ma5_slope >= MA_SLOPE_MIN and ma10_slope >= MA_SLOPE_MIN
            cond10 = latest_rsi <= RSI_MAX
            cond11 = vol_ratio >= VOL_RATIO_MIN

            if all([cond1,cond2,cond3,cond4,cond5,cond6,cond7,cond8,cond9,cond10,cond11]):
                results.append({
                    "code": code,
                    "name": stock_name,
                    "close": latest["close"],
                    "turnover_rate": turnover,
                    "mcap(元)": mcap,
                    "RSI": round(latest_rsi,2),
                    "vol_ratio": round(vol_ratio,2)
                })

            time.sleep(0.05)

        except Exception as e:
            print(f"处理 {code} 出错: {e}")
            continue

    # 保存 CSV
    file_name = f"/app/output/{name}_{today_str}.csv"
    df_result = pd.DataFrame(results)
    df_result.to_csv(file_name,index=False,encoding="utf-8-sig")
    output_files.append(file_name)
    print(f"策略 {name} 完成，共 {len(df_result)} 只股票，结果保存 {file_name}")

# ================== 邮件发送 ==================
if output_files:
    send_email(output_files)

